﻿using GN.Pay.Client.Utils;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace GN.Pay.Client.Reflection.Meta
{
    /// <summary>
    /// 元成员
    /// </summary>
    public abstract class MetaMember : IDisposable
    {
        /// <summary>
        /// 实例化 MetaMember 类新实例
        /// </summary>
        /// <param name="memberInfo">成员</param>
        protected MetaMember(MemberInfo memberInfo)
        {
            this.MemberInfo = ExceptionUtils.CheckNotNull(memberInfo, nameof(memberInfo));
            List<Attribute> atts = new List<Attribute>();
            List<ValidationAttribute> vatts = new List<ValidationAttribute>();
            var customs = this.MemberInfo.GetCustomAttributes(true);
            DisplayAttribute display = null;
            if (customs != null)
            {
                foreach (var item in customs)
                {
                    atts.Add((Attribute)item);
                    if (item is ValidationAttribute)
                    {
                        vatts.Add((ValidationAttribute)item);
                    }
                    if (item is DisplayAttribute)
                    {
                        display = (DisplayAttribute)item;
                    }
                }
            }
            if (display == null)
            {
                display = new DisplayAttribute() { Name = memberInfo.Name };
            }
            else
            {
                if (string.IsNullOrWhiteSpace(display.Name))
                {
                    display.Name = memberInfo.Name;
                }
            }
            if (memberInfo is PropertyInfo)
            {
                this.IsGeneralTypeMember = DataConvertUtils.IsAllowTargetConvert(((PropertyInfo)memberInfo).PropertyType);
            }
            else
            {
                this.IsGeneralTypeMember = DataConvertUtils.IsAllowTargetConvert(((FieldInfo)memberInfo).FieldType);
            }
            this.CustomAttributes = atts.AsReadOnly();
            this.ValidationAttributes = vatts.AsReadOnly();
            this.DisplayAttribute = display;
        }

        /// <summary>
        /// 获取友好特性
        /// </summary>
        public DisplayAttribute DisplayAttribute { get; private set; }

        /// <summary>
        /// 获取成员
        /// </summary>
        public MemberInfo MemberInfo { get; private set; }

        /// <summary>
        /// 获取成员类型
        /// </summary>
        public abstract Type MemberType { get; }

        /// <summary>
        /// 获取是否是常规类型成员(即支持直接转换)
        /// </summary>
        public bool IsGeneralTypeMember { get; private set; }

        /// <summary>
        /// 获取是否是属性
        /// </summary>
        public abstract bool IsProperty { get; }

        /// <summary>
        /// 获取成员值
        /// </summary>
        public abstract Func<object, object> GetMemberValue { get; }

        /// <summary>
        /// 设置成员值
        /// </summary>
        public abstract Action<object, object> SetMemberValue { get; }

        /// <summary>
        /// 获取自定义特性集合
        /// </summary>
        public ReadOnlyCollection<Attribute> CustomAttributes { get; private set; }

        /// <summary>
        /// 获取验证特性集合
        /// </summary>
        public ReadOnlyCollection<ValidationAttribute> ValidationAttributes { get; private set; }

        /// <summary>
        /// 响应成员名称
        /// </summary>
        /// <returns></returns>
        public sealed override string ToString()
        {
            return this.MemberInfo.Name;
        }

        /// <summary>
        /// 
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="isDispose"></param>
        protected virtual void Dispose(bool isDispose)
        {
            this.MemberInfo = null;
            this.CustomAttributes = null;
            this.ValidationAttributes = null;
        }
    }
}
